var resBase = this.scriptBase + "__res/"
	, packageName = this.packageName;
/**
 * JSDOC文档构造工具对象
 * @param {Array} bootScripts 启动脚本文件列表
 * @param {Array} packages 包名列表
 * @param {Boolean} [findDependence=false] 是否查找依赖包信息
 * @public
 */
function JSDoc(bootScripts, packages, findDependence)
{
	this.rootInfo = PackageInfo.requireRoot(bootScripts);
	var packages = this.collectPackages(packages, findDependence)
		, i = packages.length - 1
		, pkgInfo;
	this.packageInfos = new Array(i);

	for (; i >= 0; i--)
	{
		pkgInfo = PackageInfo.require(packages[i]);
		this.packageInfos[pkgInfo.name] = this.packageInfos[i] = pkgInfo;
	}
}

/**
 * 模板对象缓存
 * @type Object
 */
JSDoc.templetMap = {};

/**
 * 获取指定路径的模板对象
 * @param {String} path 模板路径
 * @return {Template} 模板对象
 */
JSDoc.getTemplate = function(path)
{
	if (this.templetMap[path])
	{
		return this.templetMap[path];
	}
	var cache = $JSI.getCacheScript(packageName, path)
		, templet = cache ? new Template(cache) : new Template(resBase + path);

	return this.templetMap[path] = templet;
}

var $p = JSDoc.prototype;

/**
 * 运行任务队列
 * @param {Array} tasks 任务队列
 * @id JSDoc.prototype.runTasks
 */
$p.runTasks = function(tasks)
{
	var i = 0;

	function task()
  {
	  if (i < tasks.length)
	  {
		  var t = tasks[i++];

		  if (typeof t == "function")
		  {
			  t();
		  }
		  setTimeout(task, 0);
	  }
  }
	task();
};

/**
 * 收集指定包信息
 * @param {Array} pkgs 包名称列表
 * @param {Boolean} [findDependence=false] 是否收集包依赖信息
 * @private
 * @return {Array} 包信息
 * @id JSDoc.prototype.collectPackages
 */
$p.collectPackages = function(pkgs, findDependence)
{
	var packageMap = {}
		, i = pkgLen = pkgs.length - 1
		, j
		, packages = []
		//just sort for js & org.xidea namespace
		, spkgs = []
		, tpkgs = []
		, objName;

	for (; i >= 0; i--)
	{
		packages[pkgs[i]] = true;
	}

	do
	{
		var dps = [];

		for (i = pkgLen; i >= 0; i--)
		{
			try
			{
				var pkgName = pkgs[i]
					, pkg = $import(pkgName + ":");

				if (pkg == null)
				{
					continue;
				}
			}
			catch (e)
			{
				continue;
			}
			packageMap[pkgName] = pkg;

			if (pkg.name != pkgName)
			{
				if (! packages[pkg.name])
				{
					packages[pkg.name] = true;
					dps.push(pkg.name);
				}
			}
			else if (findDependence)
			{
				var infm = pkg.dependenceMap;

				for (objName in infm)
				{
					var infs = infm[objName];

					for (j = infs.length - 1; j >= 0; j--)
					{
						var inf = infs[j];

						if (inf instanceof Array)
						{
							inf = inf[1];
						}

						try
						{
							inf.getNames();
							var np = inf.pkg2.name;

							if (np && ! packages[np])
							{
								packages[np] = true;
								dps.push(np);
							}
						}
						catch (e)
						{
						//依赖可能无效
						}
					}
				}
			}
		}
		pkgs = dps;
	} while (pkgs.length > 0);

	for (objName in packageMap)
	{
		packages.push(objName);
	}

	for (i= packages.length - 1; i >= 0; i--)
	{
		/^(?:js\.)|(?:org\.\xidea\.)/.test(packages[i]) ? spkgs.push(packages[i]) : tpkgs.push(packages[i]);
	}
	spkgs.sort();
	tpkgs.sort();
	return spkgs.concat(tpkgs);
};


/**
 * @public
 */
$p.gen = function(obj, anc, win)
{
	var args = obj.args
		, i = args.length - 1
		, argstrs = new Array(i);

	for (; i >= 0; i--)
	{
	
		argstrs[i] = typeof args[i] == "string" ? "'" + args[i] + "'" : args[i];
	}

	var href = "{cmd:'" + obj.cmd + "',args:[" + argstrs.join(",") + "]}";

	//alert(href)
	if (anc)
	{
		href = href + "#" + anc;
	}
	location.hash = href;
	var content = (window.frames || document.frames)[win || "content"];

	content.location.href = "wait.htm";

	setTimeout(function()
	{
		content.location.href = "controller.htm?" + href;
	}, 100);

	return false;
}

/**
 * @public
 */
$p.genMenu = function(doc)
{
	var templet = JSDoc.getTemplate("menu.xhtml");
	doc.open();
	templet.render(
	{
		jsdoc: this,
		rootInfo: this.rootInfo,
		css: resBase + "menu.css",
		packageInfos: this.packageInfos
	}, doc);

	doc.close();
};

/**
 * @public
 */
$p.genPackages = function(doc)
{
	var templet = JSDoc.getTemplate("packages.xhtml");
	doc.open();
	templet.render(
	{
		jsdoc: this,
		rootInfo: this.rootInfo,
		css: resBase + "default.css",
		packageInfos: this.packageInfos
	}, doc);

	doc.close();
}
/**
 * @public
 */
$p.genPackage = function(pkg, doc)
{
	var templet = JSDoc.getTemplate("package.xhtml");
	var pkgInfo = PackageInfo.require(pkg);

	function run()
  {
	  var infos = pkgInfo.getObjectInfos();
	  var constructors = [];
	  var functions = [];
	  var objects = [];

	  for (var i = 0; i < infos.length; i++)
	  {
		  var info = infos[i];

		  switch (info.getType())
		  {
			  case "constructor":
				  constructors.push(info);
				  break;

			  case "function":
				  functions.push(info);
				  break;

			  default:
				  objects.push(info);
		  }
	  }
	  doc.open();
	  templet.render(
	  {
		  css: resBase + "package.css",
		  constructors: constructors,
		  functions: functions,
		  objects: objects,
		  files: pkgInfo.fileInfos,
		  packageInfo: pkgInfo
	  }, doc);

	  doc.close();
  }
	var tasks = pkgInfo.getInitializers();
	tasks.push(run);
	this.runTasks(tasks);
};

/**
 * @public
 */
$p.genFile = function(file, pkg, doc)
{
	var templet = JSDoc.getTemplate("file.xhtml");
	doc.open();
	templet.render(
	{
		css: resBase + "file.css",
		fileInfo: PackageInfo.require(pkg).fileInfos[file]
	}, doc);

	doc.close();
};

/**
 * @public
 */
$p.genObject = function(obj, pkg, doc)
{
	var pkgInfo = PackageInfo.require(pkg);
	var objInfo = pkgInfo.getObjectInfoMap()[obj];

	switch (objInfo.getType())
	{
		case "constructor":
			var templet = JSDoc.getTemplate("constructor.xhtml");
			break;

		case "function":
			var templet = JSDoc.getTemplate("function.xhtml");
			break;

		case "object":
			var templet = JSDoc.getTemplate("object.xhtml");
			break;

		default:
			var templet = JSDoc.getTemplate("native.xhtml");
	}
	doc.open();
	templet.render(
	{
		css: resBase + "object.css",
		objInfo: objInfo
	}, doc);

	doc.close();
}

/**
 * @public
 */
$p.genSource = function(file, pkg, doc)
{
	var sourceEntry = SourceEntry.require(file, pkg);
	var timestamp = new Date().getTime();
	var source = sourceEntry.source.toString();
	var ds = sourceEntry.docEntries;
	var anchors = [];

	//build a list
	if (ds != null && ds[0] != null)
	{
		for (var i = 0; i < ds.length; i++)
		{
			var id = ds[i].getId();

			if (id && id.length > 0)
			{
				anchors.push(
				{
					name: id,
					position: ds[i].end
				});
			}
		}
	}

	sourceEntry.anchors = anchors;
	var lines = sourceEntry.buildLineIterator();

	var templet = JSDoc.getTemplate("source.xhtml");
	templet.beforeOutput = function()
	{
		//this.context.evalString = function(){};
	}

	doc.open();
	templet.render(
	{
		jsdoc: this,
		css: resBase + "source.css",
		lines: lines
	}, doc);

	//$log.debug("parse timeSpent:", sourceEntry.timeSpent, "gen timeSpent:", new Date().getTime() - timestamp);
	doc.close();
}

$p = null;